package com.cictec.middleware.gps.caculate;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;

import com.cictec.middleware.commons.utils.DateUtils;
import com.cictec.middleware.commons.utils.PMSUtils;
import com.cictec.middleware.commons.utils.PropertiesUtils;
import com.cictec.middleware.commons.utils.ThreadUtils;
import com.cictec.middleware.commons.utils.TimerUtils;
import com.cictec.middleware.core.entity.BusTimingPointSupply;
import com.cictec.middleware.gps.engine.caculate.entity.BusMileageData;
import com.cictec.middleware.gps.service.ScheduleService;

/**
 * 里程计算管理类
 * 
 * @author ql
 *
 */
@Repository
public class BusMileageManager extends BusMileageCaculate{

	public static Logger logger = LoggerFactory.getLogger(BusMileageEngine.class);
	
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private ScheduleService scheduleService;
	@Autowired
	private BusMileageEngine busMileageEngine;
	
	
	private ThreadPoolExecutor pool = null;
	private TimerUtils timer = null;
	private int totalSize = 0;
	
	
	public void caculateMileage(String date, List<BusTimingPointSupply> busTimingPointSupplyList){

		removeBusMileagesSupply();	// 清除redis中补传里程计算信息
		
		
		int threadMax = PropertiesUtils.getIntValue("busMileage.threads", 4);
		pool = ThreadUtils.getFixedThreadPool("bus-mileage-caculate-", threadMax);	// 获取里程计算线程池
		
		
		timer = new TimerUtils();
		totalSize = busTimingPointSupplyList.size();
		logger.debug("**************************里程计算开始******************************");
		logger.debug("【里程计算】 总计：{} 条记录", totalSize);
		
		Map<String, Integer> map = new HashMap<String, Integer>();
		for (BusTimingPointSupply busTimingPointSupply : busTimingPointSupplyList) {
			String key = busTimingPointSupply.getSupDate();
			if(map.containsKey(key)){
				map.put(key, (int) map.get(key) + 1);
			}else{
				map.put(key, 1);
			}
		}
		for (String key : map.keySet()) {
			logger.debug("【里程计算】{} 共：{} 条记录", key, map.get(key));
			// 加载对应日期的时刻表
			scheduleService.loadLinesSchedule(key);
		}
		
		// 使用线程安全的Vector
		Vector<Future<String>> threads = new Vector<Future<String>>();
		int index = 1;
		for (BusTimingPointSupply supply : busTimingPointSupplyList) {
//			pool.submit(new MileageCaculateRunable(supply, index));
			threads.add(pool.submit(new MileageCaculateRunable(supply, index)));
			index ++;
		}
		
		for (Future<String> future : threads) {
			// 等待所有线程执行完毕
			try {
				Object result = future.get();
				logger.debug(result.toString());
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		
		
		for (String cdate : map.keySet()) {
			logger.debug("【里程计算】【删除时刻表】{} ", cdate);
			scheduleService.clearScheduleTable(cdate);
		}
		
		logger.debug("【里程计算】{} 里程计算任务结束，共{}个任务，耗时：{}", date, busTimingPointSupplyList.size(), timer.getTotalLostTimes());
		
		
	}
	
	/**
	 * 清除redis中补传里程计算信息
	 */
	private void removeBusMileagesSupply() {
		String redisKey = "busMileages_supply";
		if (stringRedisTemplate.hasKey(redisKey)) {
			HashOperations<String, String, String> ops = stringRedisTemplate.opsForHash();
			Set<String> keys = ops.keys(redisKey);
			try {
				String date = DateUtils.getDate();
				for (String keyValue : keys) {
					Date fieldDate = DateUtils.parseDate(keyValue.split("-")[0], "yyyyMMdd");
					if (DateUtils.dayInterval(fieldDate, DateUtils.parseDate(date)) > 1) {
						// 时间间隔超过15天的删除
						ops.delete(redisKey, keyValue);
					}
				}
			} catch (ParseException e) {
				e.printStackTrace();
				stringRedisTemplate.delete(redisKey);
			}
		}
	}
	
	/**
	 * 里程计算线程
	 * @author ql
	 *
	 */
	class MileageCaculateRunable implements Callable<String> {

		private BusTimingPointSupply supply;
		private int index;

		public MileageCaculateRunable(BusTimingPointSupply supply, int index) {
			this.supply = supply;
			this.index = index;
		}

		@Override
		public String call() throws Exception {
			
			try {
				BusMileageData busMileageData = busMileageEngine.getInitBusMileageData(supply);
				String devCode = busMileageData.devCode;
				String busNumber = busMileageData.plate;
				String date = busMileageData.date;
				logger.debug("{}-{}：开始计算 总计{}条记录，第 {} 条 ", devCode, busNumber, totalSize, index);
				
				busMileageEngine.executeMileage(busMileageData);
				
				busTimingPointService.saveTimingPointSupply(devCode, date, null, "0");// 更新该车辆里程已经计算完成
				String resultMsg = PMSUtils.format("{}-{}：结束,第{}条", devCode, busNumber, index);
				return resultMsg;
				
			} catch (Exception e) {
				e.printStackTrace();
				return e.getMessage();
			}
		}
	}
}
